
#include "Globals.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TcmForm *cmForm;
//---------------------------------------------------------------------------
__fastcall TcmForm::TcmForm(TComponent* Owner)
 : TForm(Owner)
{
}


//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::FormCreate(TObject *Sender)
{
  getcwd( cur_dir, MAXPATH );
}


//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::Graphics1Click(TObject *Sender)
{
  LONG ofStart[3]  =
  {
    0x00C06321,
    0x00C08F80,
    0
  };
  //
  LONG ofBegin;
  //
  TMenuItem *m = (TMenuItem *)Sender;

  //
  if ( !cpu.rom ) return;

  ofBegin = Snes2Pc( ofStart[ m->Tag ] );
  // Decompress the block
  Decompress( ofBegin );
}


//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::RecompressBlock1Click(TObject *Sender)
{
  FILE *tf,
       *rf,
       *df;
  //-----------------
  char file1[MAXPATH];
  char file2[MAXPATH];
  char file3[MAXPATH];
  //------------------
  char buf[256];
  char tuf[256];
  LONG ofBegin;
  LONG ofEnd;
  LONG Lof;
  //
  int  flag;


  if ( !cpu.ram || !cpu.rom ) return;

  //
  FOpen->InitialDir = cur_dir;
  FOpen->FileName   = "";
  FOpen->Filter     = "All Files | *.*";

  if ( FOpen->Execute( ) )
  { //
    strcpy( file1, FOpen->FileName.c_str( ) );
    tf = fopen( file1, "rt" );
    if ( !tf ){
      ShowMessage( "Error: Could not open TEXT SOURCE file." );
      fcloseall( );
      return;
    }
  }
  else
    return;

  //---------------------------//
  //                           //
  //---------------------------//
  ListBox1->Clear( );
  while( fgets( buf, 256, tf ) )
  { //            TAG  SOURCE File  Start  End
    sscanf( buf, "%s   %s           %X     %X",
            &tuf,      // Tag
            &file2,    // Source File
            &ofBegin,  // Start offset
            &ofEnd     // Max posiion
          );
    //-----------------------------
    // Recompress the block
    if ( !strncmpi( buf, ".COMP", 5 ) )
    { // Try to open the file
      df = fopen( file2, "rb" );
      if ( !df )
      {
        ListBox1->Items->Add( "Fatal Error: Could not open \"" + ExtractFileName( file2 ) + "\"." );
        continue;;
      }
      else
      {
        fread( &cpu.ram[0x10000], 1, Lof = FileSize( df ), df );
        fclose( df );
      }
      //
      flag = Recompress( ofBegin, ofEnd, Lof );
      switch( (short)flag )
      {
        case -2: ListBox1->Items->Add( "Error: Data size too large to recompress. [ " + ExtractFileName( file2 ) + " ] [ " + IntToStr( flag >> 16 ) + " BYTES over ]"); break;
        case -3: ListBox1->Items->Add( "Error: Invalid data block. [ " + ExtractFileName( file2 ) + " ] " ); break;
        //---------------------------
        case 0 :
        default: ListBox1->Items->Add( "Success: Data was recompressed completely! [ " + ExtractFileName( file2 ) + " ] " ); break;
      }
    }
    //
    CheckMSG( );
  }
}


//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::OpenROMFile1Click(TObject *Sender)
{
  FILE *rf;
  LONG Lof;

  FOpen->InitialDir = cur_dir;
  FOpen->FileName   = "";
  FOpen->Filter     = "Snes file | *.smc";

  if ( FOpen->Execute( ) )
  { //
    strcpy( romf, FOpen->FileName.c_str( ) );
    rf = fopen( romf, "rb" );
    if ( !rf ){
      ShowMessage( "Error: Could not open ROM file." );
      return;
    }
    //
    cpu.Length = FileSize( rf );
    if ( cpu.Length & 0x0200 )
    { //
      cpu.Header = 0x0200;
//      fseek( rf, 0x0200, SEEK_SET );
    }
    //
    cpu.rom = (BYTE *)malloc( cpu.Length );
    cpu.ram = (BYTE *)malloc( 0x20000 );
    //
    if ( !cpu.ram || !cpu.rom )
    { //
      _free( cpu.rom );
      _free( cpu.ram );
      fclose( rf );
      //
      ShowMessage( "Fatal Error: Could not allocate needed memory." );
      cmForm->Close( );
      return;
    }

    // Read in the rom data
    fread( cpu.rom, 1, cpu.Length, rf );
    cpu.rom += cpu.Header;
    fclose( rf );
    // Check and validate the ROM
    if ( strncmp( &cpu.rom[ 0xFFC0 ], "FARLANDSTORY2", 13 ) )
    {
      ShowMessage( "This is not the correct ROM.\n"
                   "Please load the correct ROM file."
                 );
      //
      _free( cpu.ram );
      cpu.rom += cpu.Header;
      _free( cpu.rom );
      return;
    }
  }
}



//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::SaveROMFile1Click(TObject *Sender)
{
  FILE *rf;

  if ( !romf[0] || !cpu.ram || !cpu.rom ) return;
  //
  rf = fopen( romf, "wb" );
  if ( !rf )
  {
    ShowMessage( "Error: Could not open ROM file." );
    return;
  }
  //
  fwrite( (cpu.rom - cpu.Header), 1, cpu.Length , rf );
  //
  fclose( rf );
  ShowMessage( "\"" + ExtractFileName( romf ) + "\" has been saved!" );
}


//--------------------------//
//                          //
//--------------------------//
void __fastcall TcmForm::Exit1Click(TObject *Sender)
{
  cpu.rom += cpu.Header;
  _free( cpu.rom );
  _free( cpu.ram );
  //
  Close( );
}


//--------------------------//
// Decompression Subroutine //
//--------------------------//
int  __fastcall TcmForm::Decompress( LONG ofStart )
{
  #define WRAM( x ) *(WORD *)&ram[ x ]

  FILE *cf,
       *df,
       *tf;
  BYTE *rom  = cpu.rom;
  BYTE *win  = cpu.ram;
  BYTE *ram  = &cpu.ram[0x00200];
  BYTE *comp = &cpu.ram[0x10000];
  LONG posi = ofStart;
  LONG record_posi;
  WORD index,
       CompSize;
  char buf[ MAXPATH << 1 ];
  char tuf[ MAXPATH << 1 ];

  // Create the directory
  sprintf( buf, "%s\\Comp\\", cur_dir, ( ofStart + cpu.Header ) );
  mkdir( buf );
  //
  sprintf( buf, "%s\\Comp\\%08X.txt", cur_dir, ( ofStart + cpu.Header ) );
  cf = fopen( buf, "wt" );
  if ( !cf ){
    ShowMessage("Error: Could not open 'TEXT SOURCE' file." );
    fclose( cf );
    return -1;
  }

  //
  index = 0;
  ListBox1->Clear( );
  memset( win, 0x00, 0xFF );
  // Size of Compressed Data
  WRAM(0x3A) = WGET( rom, posi );
  posi      += 2;
  WRAM(0x14) = 0;
  ram[0x42]  = 0;
  ram[0x44]  = 0;
  ram[0x45]  = 0;
  //-------------------------//
  // Start the decompression //
  //-------------------------//
  while( *(short *)&ram[0x3A] > 0 )
  { // get testing WORD
    ram[0x38]  = rom[ posi++ ];
    WRAM(0x3A)-= 1;
    ram[0x44]  = 8;
    //
    while( ram[0x44]-- )
    { //-----------------------//
      //                       //
      //-----------------------//
      if ( !(ram[0x38] & 0x01) )
      { // Regular data routine
        comp[ WRAM(0x14) ] = rom[ posi ];
        win[ ram[0x42] ]   = rom[ posi ];
        WRAM(0x14) += 1;
        ram[0x42]  += 1;
        posi       += 1;
        //
        WRAM(0x3A) -= 1;
      }
      else
      { // Compressed data
        WRAM(0x48) = rom[ posi++ ] + 1;
        ram[0x46]  = ( ram[0x42] + rom[ posi++ ] );
        //
        WRAM(0x3A) -= 2;
        // Copy the data
        while( WRAM(0x48) > 0 )
        { //
          comp[ WRAM(0x14) ] = win[ ram[0x46] ];
          win[ ram[0x42 ] ]  = win[ ram[0x46] ];
          //
          WRAM(0x14) += 1;
          WRAM(0x48) -= 1;
          ram[0x46]  += 1;
          ram[0x42]  += 1;
        }// WEND
      }// END IF

      // Adjust the BITS
      ram[0x38] >>= 1;
    }// WEND - ram[0xB0] > 0
  }// WEND reg.y > 0

  //-----------------------//
  //                       //
  //-----------------------//
  sprintf( buf, "%s\\Comp\\FS2_%X.dat", cur_dir, ( ofStart + cpu.Header ) );
  df = fopen( buf, "wb" );
  //---------------
  if ( !df )
  { //
    ShowMessage( "Fatal Error: Could not open output file. Closing decompressor..." );
    fclose( cf );
    fclose( df );
    return -2;
  }
  // Dump the data
  fwrite( comp, 1, WRAM(0x14), df );
  fclose( df );
  //
  sprintf( tuf, "Sucessfully decompressed \"%s\"", ExtractFileName( AnsiString(buf) ).c_str( ) );
  ListBox1->Items->Add( tuf );

  // record decomp data
  fprintf( cf, ".COMP %s  %08X  %08X\n", buf, ofStart, posi );
}


//--------------------------//
// Recompression Subroutine //
//--------------------------//
int  __fastcall TcmForm::Recompress( LONG ofStart, LONG ofEnd, LONG Lof )
{
  #define WRAM( x ) *(WORD *)&ram[ x ]

  FILE *cf,
       *df,
       *tf;
  BYTE *rom  = cpu.rom;
  BYTE *win  = cpu.ram;
  BYTE *ram  = &cpu.ram[0x00200];
  BYTE *romb = &cpu.ram[0x01000];
  BYTE *comp = &cpu.ram[0x10000];

  LONG posi = ofStart;
  LONG bit_posi;
  LONG rom_posi;
  LONG ram_posi;

  WORD index,
       bck_posi,
       most,
       CompSize,
       count;

  BYTE most_posi;

  //
  index = 0;
  ListBox1->Clear( );
  //
  memset( win, 0x00, 0xFF );
  ram[0x42]  = 0;
  //
  rom_posi = 1;
  ram_posi = 0;
  bit_posi = 0;
  //-------------------------//
  // Start the decompression //
  //-------------------------//
  while( ram_posi < Lof )
  { //
    index     = 8;
    ram[0x00] = 0;
    // Loop through 8 bits of data
    while( index-- )
    {	// this is the regular data routine
      bck_posi = 0;
      most     = 0;

      //---------------------------//
      // Loop through all the data //
      //---------------------------//
      while( bck_posi < 256 )
      { //
        if ( win[ bck_posi ] == comp[ ram_posi ] )
        { //
          count = 0;
          while( win[ (bck_posi + count) & 0xFF ] == comp[ ram_posi + count ] &&
                 (ram_posi + count) < Lof &&
                 ((bck_posi + count) & 0xFF) < 0x0100 &&
                 count < 0x0100
               )
            //
            count++;
          //
          // Check for better matches
          if ( count > most )
          {
            most      = count;
            most_posi = bck_posi;
            //
            if ( most >= 0x0100 )
            { //
              most = 0x0100;
              break;
            }
          }//
        }//

        bck_posi++;
      }// WEND - bck_posi < ram_posi

      //----------------------------//
      // Compress / store the data. //
      //----------------------------//
      if ( most > 2  )
      { //
        romb[ rom_posi++ ] = ( most - 1 );
        romb[ rom_posi++ ] = ( most_posi - ram[0x42] );
//        ram_posi += most;
        // Copy data to the buffer
        while( most-- )
          win[ ram[0x42]++ ] = comp[ ram_posi++ ];
        // Store the BITS
        ram[0x00] >>= 1;
        ram[0x00]  |= 0x80;
      }
      else
      { // Write STATIC data
        romb[ rom_posi ] = comp[ ram_posi ];
        win[ ram[0x42] ] = comp[ ram_posi ];
        //
        ram[0x42]++;
        rom_posi++;
        ram_posi++;
        // Store the BITS
        ram[0x00] >>= 1;
      }// END IF
    }// WEND - index > 0

    //-------------------------//
    // Record data and do more //
    //-------------------------//
    romb[ bit_posi ] = ram[0x00];
    bit_posi  = rom_posi;
    rom_posi++;
  }// WEND - ram_posi < Lof

  //-------------------------------//
  // Can we write the data to ROM? //
  //-------------------------------//
  if ( (bit_posi + posi) <= ofEnd )
  { // write new data
    *(WORD *)&rom[ posi ] = bit_posi;
    posi                 += 2;
    // copy over the compressed data
    memcpy( &rom[ posi ], romb, bit_posi );
  }
  else
  { // Data size is too large!
    return (-2) + ( ((bit_posi + posi) - ofEnd) << 16);
  }

  // All was good!
  return 0;
}









